package net.qhzw.vip.qiyu.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import net.qhzw.vip.qiyu.dto.OrderCountData;
import net.qhzw.vip.qiyu.dto.ShopCartOrderMergerDto;
import net.qhzw.vip.qiyu.entity.*;
import net.qhzw.vip.qiyu.evnet.CancelOrderEvent;
import net.qhzw.vip.qiyu.evnet.ReceiptOrderEvent;
import net.qhzw.vip.qiyu.evnet.SubmitOrderEvent;
import net.qhzw.vip.qiyu.feign.ShopFeignClient;
import net.qhzw.vip.qiyu.handler.ApiException;
import net.qhzw.vip.qiyu.mapper.*;
import net.qhzw.vip.qiyu.param.OrderParam;
import net.qhzw.vip.qiyu.service.AreaService;
import net.qhzw.vip.qiyu.service.DeliveryManService;
import net.qhzw.vip.qiyu.service.LogisticsAreaService;
import net.qhzw.vip.qiyu.service.OrderService;
import net.qhzw.vip.qiyu.util.PageAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author lgh on 2018/09/15.
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private SkuMapper skuMapper;

    @Autowired
    private OrderItemMapper orderItemMapper;

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private ApplicationEventPublisher eventPublisher;

    @Autowired
    private DeliveryMapper deliveryMapper;

    @Autowired
    private ShopFeignClient shopFeignClient;

    @Autowired
    private LogisticsAreaService logisticsAreaService;


    @Autowired
    private AreaService areaService;

    @Autowired
    private DeliveryManService deliveryManService;

    @Override
    public Order getOrderByOrderNumber(String orderNumber) {
        return orderMapper.getOrderByOrderNumber(orderNumber);
    }

    @Override
    @CachePut(cacheNames = "ConfirmOrderCache", key = "#userId")
    public ShopCartOrderMergerDto putConfirmOrderCache(Long userId, ShopCartOrderMergerDto shopCartOrderMergerDto) {
        return shopCartOrderMergerDto;
    }

    @Override
    @Cacheable(cacheNames = "ConfirmOrderCache", key = "#userId")
    public ShopCartOrderMergerDto getConfirmOrderCache(Long userId) {
        return null;
    }

    @Override
    @CacheEvict(cacheNames = "ConfirmOrderCache", key = "#userId")
    public void removeConfirmOrderCache(Long userId) {
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Order> submit(Long userId, ShopCartOrderMergerDto mergerOrder) {
        List<Order> orderList = new ArrayList<>();
        // 通过事务提交订单
        eventPublisher.publishEvent(new SubmitOrderEvent(mergerOrder, orderList));
        // 插入订单
        orderList.forEach(order -> orderMapper.insert(order));
        List<OrderItem> orderItems = orderList.stream()
                .flatMap(order -> order.getOrderItems().stream()).collect(Collectors.toList());
        // 插入订单项，返回主键
        orderItemMapper.insertBatch(orderItems);
        return orderList;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delivery(Order order) {
        orderMapper.updateById(order);
        // 发送用户发货通知
        Map<String, String> params = new HashMap<>(16);
        params.put("orderNumber", order.getOrderNumber());
        Delivery delivery = deliveryMapper.selectById(order.getDvyId());
//		params.put("dvyName", delivery.getDvyName());
//		params.put("dvyFlowId", order.getDvyFlowId());
//		smsLogService.sendSms(SmsType.NOTIFY_DVY, order.getUserId(), order.getMobile(), params);


    }

    @Override
    public List<Order> listOrderAndOrderItems(Integer orderStatus, DateTime lessThanUpdateTime) {
        return orderMapper.listOrderAndOrderItems(orderStatus, lessThanUpdateTime);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelOrders(List<Order> orders, Byte status) {
        orderMapper.cancelOrders(orders, status);
        List<OrderItem> allOrderItems = new ArrayList<>();
        for (Order order : orders) {
            List<OrderItem> orderItems = order.getOrderItems();
            allOrderItems.addAll(orderItems);
            eventPublisher.publishEvent(new CancelOrderEvent(order));
        }
        if (CollectionUtil.isEmpty(allOrderItems)) {
            return;
        }
        Map<Long, Integer> prodCollect = new HashMap<>(16);
        allOrderItems.stream().collect(Collectors.groupingBy(OrderItem::getProdId)).forEach((prodId, orderItems) -> {
            int prodTotalNum = orderItems.stream().mapToInt(OrderItem::getProdCount).sum();
            prodCollect.put(prodId, prodTotalNum);
            productMapper.returnStock(prodId, prodTotalNum);
        });
        //productMapper.returnStock(prodCollect);

        Map<Long, Integer> skuCollect = new HashMap<>(16);
        allOrderItems.stream().collect(Collectors.groupingBy(OrderItem::getSkuId)).forEach((skuId, orderItems) -> {
            int prodTotalNum = orderItems.stream().mapToInt(OrderItem::getProdCount).sum();
            skuCollect.put(skuId, prodTotalNum);
            skuMapper.returnStock(skuId, prodTotalNum);
        });
        //skuMapper.returnStock(skuCollect);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void confirmOrder(List<Order> orders) {
        orderMapper.confirmOrder(orders);
        for (Order order : orders) {
            eventPublisher.publishEvent(new ReceiptOrderEvent(order));
        }

    }

    @Override
    public List<Order> listOrdersDetialByOrder(String orderNumber, Integer shippingType, Integer status, Integer isPayed, Date startTime, Date endTime) {
        return orderMapper.listOrdersDetialByOrder(orderNumber, shippingType, status, isPayed, startTime, endTime);
    }

    @Override
    public IPage<Order> pageOrdersDetialByOrderParam(Page<Order> page, OrderParam orderParam) {
        Long shopId = orderParam.getShopId();
        Shop shop = shopFeignClient.findById(shopId).getData();
        if (shop == null) {
            throw new ApiException("暂无法获取商户信息, 请联系管理员!");
        }
        orderParam.setShopId(0L);
        if (shop.getShopType() == 1 || shop.getShopType() == 2) {
            throw new ApiException("该商户无法查看订单信息, 请联系管理员!");
        } else if (shop.getShopType() == 3) {
            orderParam.setShopId(shopId);
        } else if (shop.getShopType() == 0) {
            //超级管理员
            orderParam.setShopId(0L);
        } else if (shop.getShopType() == 4) {
            //4:物流
            Long areaId = logisticsAreaService.findAaerIdByShopId(shopId);
            List<Long> areaIds = areaService.srchAllChildrenIdByPid(areaId);
            if (!CollectionUtils.isEmpty(areaIds)){
                areaIds.add(areaId);
            }else {
                areaIds = new ArrayList<>(1);
                areaIds.add(areaId);
            }
            List<Long> deliveryIds = deliveryMapper.selectIdByAreaId(areaIds);
            if (CollectionUtils.isEmpty(deliveryIds)) {
                deliveryIds = new ArrayList<>(1);
                deliveryIds.add(0L);
            }
            orderParam.setDeliveryIds(deliveryIds);
        } else if (shop.getShopType() == 5) {
            //5:提车点
            List<Long> deliveryIds = deliveryMapper.selectIdByShop(shopId);
            if (CollectionUtils.isEmpty(deliveryIds)) {
                deliveryIds = new ArrayList<>(1);
                deliveryIds.add(0L);
            }
            orderParam.setDeliveryIds(deliveryIds);
        } else {
            throw new ApiException("该商户无法查看订单信息, 请联系管理员!");
        }
        List<Order> orders = orderMapper.listOrdersDetialByOrderParam(new PageAdapter(page), orderParam);
        //List<Order> reset = reDeliveryMan(orders);
        page.setRecords(orders);
        page.setTotal(orderMapper.countOrderDetial(orderParam));
        return page;
    }

    private List<Order> reDeliveryMan(List<Order> orders) {
        List<Long> deliveryIds = orders.stream().map(Order::getDeliveryId).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(deliveryIds)){
            return orders;
        }
        List<DeliveryMan> deliverymens = deliveryManService.queryDetailedAddrByIds(deliveryIds);
        if (!CollectionUtils.isEmpty(deliverymens)){
            for (Order order : orders) {
                for (DeliveryMan deliveryMAN : deliverymens) {
                    if (order.getDeliveryId().equals(deliveryMAN.getId())){
                        order.setDeliveryMan(deliveryMAN);
                        continue;
                    }
                }
            }

        }
        return orders;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteOrders(List<Order> orders) {
        orderMapper.deleteOrders(orders);
    }

    @Override
    public OrderCountData getOrderCount(Long userId) {
        return orderMapper.getOrderCount(userId);
    }


}
